#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> //struct sockaddr_in
#include <arpa/inet.h>  //inet_ntoa()  inet_addr()
#include <unistd.h>     //close()
#include <cstring>
using namespace std;
/*
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    功能：将指定的套接字，连接到给定的地址上(客户端用的)
    参数1：要连接的套接字文件描述符
    参数2：通用地址信息结构体(服务器的地址信息)
    参数3：参数2的大小
    返回值：成功返回0，失败返回-1并置位错误码


网络通信中为什么喜欢用fgets读入？
1.fegets是c语言的函数，有更好的性能和c++兼容性
2.指定读取缓冲大小，精准控制
3.所有平台都原生支持,良好的跨平台性(cin必须用c++标准库才能用)
*/
#define CNT_SEVER_PORT 9090
#define CNT_SEVER_IP "172.21.67.187"
int main()
{
    // 1.创建套接字
    int socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if (socketfd == -1)
    {
        perror("socket error");
        return -1;
    }
    cout << "socket success socketfd = " << socketfd << endl;

    // 2.连接服务器
    // 2.1 填充要连接的服务器地址信息结构体
    struct sockaddr_in server_in;
    server_in.sin_family = AF_INET;
    server_in.sin_port = htons(CNT_SEVER_PORT);
    server_in.sin_addr.s_addr = inet_addr(CNT_SEVER_IP);
    // 2.2 连接服务器
    if (connect(socketfd, (struct sockaddr *)&server_in, sizeof(server_in)) == -1)
    {
        perror("connect error");
        return -1;
    }
    cout << "connect success" << endl;

    // 3.数据收发
    char buf[128] = "";
    while (1)
    {
        // 清空容器中的内容
        bzero(buf, sizeof(buf));
        // 从标准输入中读取消息
        cout << "请输入要发送的消息：";
        fgets(buf, sizeof(buf), stdin);
        buf[strlen(buf) - 1] = '\0'; // 将换行改成 '\0'
        if (strcmp(buf, "q") == 0)
        {
            cout << "客户端退出" << endl;
            break;
        }
        // 将消息发送给服务器
        if (send(socketfd, buf, strlen(buf), 0) == -1)
        {
            perror("send error");
            return -1;
        }
        // 从服务器接收消息
        int recv_len = recv(socketfd, buf, sizeof(buf), 0);
        if (recv_len == -1)
        {
            perror("recv error");
            return -1;
        }
        else if (recv_len == 0)
        {
            cout << "服务器下线" << endl;
            break;
        }
        buf[recv_len] = '\0'; // 除去服务端发过来的换行同时防止发送时候的缓冲数据打印出来
        cout << "服务器回复：" << buf << endl;
    }

    // 4.关闭套接字q
    close(socketfd);
    return 0;
}